package com.jintian.smart.kernel.autoconfigure.model;

import com.jintian.smart.kernel.common.util.StringUtil;
import com.jintian.smart.kernel.core.annotation.expr.ExprFn;
import com.jintian.smart.kernel.core.expr.IExpressionCalc;
import com.jintian.smart.kernel.core.expr.IFunctionRepository;
import lombok.extern.slf4j.Slf4j;
import org.beetl.core.GroupTemplate;
import org.beetl.ext.spring6.BeetlGroupUtilConfiguration;
import org.beetl.sql.core.ConditionalSQLManager;
import org.beetl.sql.core.SQLManager;
import org.beetl.sql.core.engine.template.BeetlTemplateEngine;
import org.hibernate.validator.internal.constraintvalidators.bv.time.futureorpresent.FutureOrPresentValidatorForReadableInstant;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Set;

/**
 * masterContext自定义Bean处理
 */
@Slf4j
@Configuration(proxyBeanMethods = false)
public class MasterCustomBeanProcessor extends BeetlGroupTemplateProcesser implements BeanPostProcessor, ApplicationContextAware {
    private ApplicationContext masterContext;

    //    TODO 有注入问题，未发现对象的使用场景，临时注释
    //    private final FutureOrPresentValidatorForReadableInstant futureOrPresentValidatorForReadableInstant;
    //
    //    public MasterCustomBeanProcessor(FutureOrPresentValidatorForReadableInstant futureOrPresentValidatorForReadableInstant) {
    //        super();
    //        this.futureOrPresentValidatorForReadableInstant = futureOrPresentValidatorForReadableInstant;
    //    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.masterContext = applicationContext;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @EventListener
    private void onApplicationRefresh(ContextRefreshedEvent event) {
        this.scanExprFn(event.getApplicationContext());
        if (this.masterContext == event.getApplicationContext()) {
            this.copyBeetlGroupTemplateToSqlManager(masterContext);
        }

//        BeetlGroupUtilConfiguration bean = event.getApplicationContext().getBean(BeetlGroupUtilConfiguration.class);
        ConditionalSQLManager conditionalSQLManager = event.getApplicationContext().getBean(ConditionalSQLManager.class);
        if (conditionalSQLManager != null) {
            for (SQLManager sqlManager : conditionalSQLManager.getSqlManagerMap().values()) {
                GroupTemplate groupTemplate = ((BeetlTemplateEngine) sqlManager.getSqlTemplateEngine()).getBeetl().getGroupTemplate();
                processBeetlGroupTemplate(event.getApplicationContext(), groupTemplate);
            }
        }

        // this.scanSqlManagerBeetlTemplate(event.getApplicationContext());
    }

    private void scanExprFn(ApplicationContext scanContext) {
        IFunctionRepository repository = this.masterContext.getBean(IFunctionRepository.class);
        Set<String> exprFnSet = new HashSet<>();
        scanContext.getBeansWithAnnotation(ExprFn.class).values().forEach(bean -> {
            ReflectionUtils.doWithMethods(bean.getClass(), new ReflectionUtils.MethodCallback() {
                @Override
                public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
                    exprFnSet.addAll(repository.registerMethod(null, method, bean));
                }
            }, new ReflectionUtils.MethodFilter() {
                @Override
                public boolean matches(Method method) {
                    return Modifier.isPublic(method.getModifiers()) && Modifier.isStatic(method.getModifiers());
                }
            });
        });
        IExpressionCalc IExpressionCalc = this.masterContext.getBean(IExpressionCalc.class);
        IExpressionCalc.reloadFunctions();
        if (exprFnSet.size() > 0) {
            StringBuffer sb = new StringBuffer("注册").append(scanContext.getId())
                    .append(".java计算表达式函数:\n----------------------------------------------------------\n");
            sb.append(StringUtil.join(exprFnSet.toArray(new String[0]), ","));
            log.info("{}\n----------------------------------------------------------", sb.toString());
        }
    }
}
